home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / timer / sun4.md / timerIntersil.c < prev    next >
C/C++ Source or Header  |  1990-09-06  |  20KB  |  779 lines

  1. /*
  2.  * timerIntersil.c --
  3.  *
  4.  *    This file contains routines that manipulate the Intersil
  5.  *    ICM7170 real-time clock chip for the SUN-3.
  6.  *    (For a detailed explanation of the chip, see the data sheet
  7.  *    for the ICM7170 [Dec. 1985, 301680-005].)
  8.  *
  9.  *    The Intersil chip is used to provide perdiodic interrupts
  10.  *    and contains a set of free-running counters that keep track of time.
  11.  *    The routine in this file are used to setup the chip to
  12.  *    cause interrupts every 10 milliseconds (100th of second)
  13.  *    and maintain the time since the counters were initialized.
  14.  *
  15.  *      According to the Sun-3 Architecture manual (rev. 2.0, 25 July
  16.  *      1985), The chip's "interrupt output signal causes an interrupt
  17.  *      request on level 5 or 7 via the interrupt register." The routines
  18.  *      in this file set and reset the level-5 interrupt enable bit in the
  19.  *      interrupt register.  It also assumed that level-7 interrupts are
  20.  *      disabled.
  21.  *
  22.  *    The AMD timer chip on the Sun-2 provides several timers and
  23.  *    two of them are used by the Timer_ module for controlling the 
  24.  *    callback queue and profiling. Unfortunately the Intersil chip 
  25.  *    provides just one timer. The two timers used by the Timer module
  26.  *    are built from the chip's single timer. Thus whenever the
  27.  *    Intersil chip's timer interrupts, the two virtual timers
  28.  *    can appear to have gone off. Unlike the timers on the Sun-2,
  29.  *    the virtual timers can not cause indepdent interrupts.
  30.  *
  31.  *    The free-running counters on the Intersil chip can be used to
  32.  *    keep the time of day in Unix format (i.e. the time since 1/1/1970).
  33.  *    The counter is used here to keep track of the amount of time
  34.  *    since the system was booted.
  35.  *
  36.  *    Additional Timer_Counter routines are provided to convert from/to
  37.  *    32-bit interval values (described in timerClock.c) to/from time.
  38.  *    The interval represents an machine-dependent format for small 
  39.  *    time values. For the Sun-3, an interval is a fraction of second
  40.  *    because it is easily converted to the units that the free-running 
  41.  *    counters count in.
  42.  *
  43.  * Copyright 1986 Regents of the University of California
  44.  * All rights reserved.
  45.  */
  46.  
  47.  
  48. #ifndef lint
  49. static char rcsid[] = "$Header: /sprite/src/kernel/timer/sun4.md/RCS/timerIntersil.c,v 9.2 90/09/06 18:18:41 jhh Exp $ SPRITE (Berkeley)";
  50. #endif not lint
  51.  
  52. #include "sprite.h"
  53. #include "mach.h"
  54. #include "machConst.h"
  55. #include "devAddrs.h"
  56. #include "timer.h"
  57. #include "timerInt.h"
  58. #include "timerIntersilInt.h"
  59. #include "spriteTime.h"
  60. #include "stdio.h"
  61.  
  62.  
  63. /* For profiling call */
  64. #include "prof.h"
  65.  
  66. static TimerDevice *timerRegsPtr = (TimerDevice *) DEV_TIMER_ADDR;
  67.  
  68. /*
  69.  * Flags to indicate whether a timer is enabled or not.
  70.  */
  71. static Boolean profileIntrsWanted = FALSE;
  72. static Boolean callbackIntrsWanted = FALSE;
  73.  
  74. /*
  75.  * Initial state of the timer's interrupt enable/disable bit.
  76.  */
  77.  
  78. static int timerIntrState = INTR_DISABLE;
  79. static int timerActive = FALSE;
  80.  
  81. /*
  82.  * Frequency of the timer's interrupts.
  83.  */
  84. #define TIMER_INTR_FREQ     S100TH_SEC_MASK
  85.  
  86. /*
  87.  * Initial values of the free-running counters.
  88.  * According to the Intersil data sheet, the month and day
  89.  * counters start counting at 1.
  90.  */
  91. static    IntersilCounters    initialCounter = {
  92.     0,    /* hundredths */
  93.     0,    /* hours */
  94.     0,    /* minutes */
  95.     0,    /* seconds */
  96.     1,    /* month */
  97.     1,    /* day */
  98.     0,    /* year */
  99.     0,    /* dayOfWeek */
  100. };
  101.  
  102.  
  103. /*
  104.  * Routine to calculate a time value from the values in the free-running
  105.  * counters.
  106.  */
  107.  
  108. static void CountersToTime _ARGS_((register IntersilCounters *counterPtr, register Time *timePtr));
  109. int Timer_TimerServiceInterrupt();
  110.  
  111. /*
  112.  * Timer interval expressed as an integer and as a Time. This is the
  113.  * period between callbacks, so it is actually twice the timer period
  114.  * since we callback every other time. A tick on a sun3 is 1 ms and
  115.  * we callback every 20 ms.
  116.  */
  117.  
  118. static unsigned int interval = TIMER_CALLBACK_INTERVAL_APPROX / 1000;
  119. static Time time = { 0, TIMER_CALLBACK_INTERVAL_APPROX};
  120.  
  121. /*
  122.  * Constants used to convert the contents of the free-running counters
  123.  * to time in seconds and microseconds.
  124.  */
  125.  
  126. #define SECS_PER_MIN    60
  127. #define SECS_PER_HOUR    SECS_PER_MIN * 60
  128. #define SECS_PER_DAY     SECS_PER_HOUR * 24
  129. #define SECS_PER_YEAR    SECS_PER_DAY * 365
  130.  
  131. /*
  132.  * Number of seconds since the beginning of the year to the
  133.  * beginning of a month.
  134.  */
  135. static int accumSecsPerMonth[13] = {
  136.     0,        /* nothing */
  137.     0 * SECS_PER_DAY,        /* Jan */
  138.     31 * SECS_PER_DAY,        /* Feb */
  139.     59 * SECS_PER_DAY,        /* Mar */
  140.     90 * SECS_PER_DAY,        /* Apr */
  141.     120 * SECS_PER_DAY,        /* May */
  142.     151 * SECS_PER_DAY,        /* Jun */
  143.     181 * SECS_PER_DAY,        /* Jul */
  144.     212 * SECS_PER_DAY,        /* Aug */
  145.     243 * SECS_PER_DAY,        /* Sep */
  146.     273 * SECS_PER_DAY,        /* Oct */
  147.     304 * SECS_PER_DAY,        /* Nov */
  148.     334 * SECS_PER_DAY,        /* Dec */
  149. };
  150.  
  151. /*
  152.  * Version of above for leap years.
  153.  */
  154. static int accumSecsPerMonthLeap[13] = {
  155.     0,        /* nothing */
  156.     0 * SECS_PER_DAY,        /* Jan */
  157.     31 * SECS_PER_DAY,        /* Feb */
  158.     60 * SECS_PER_DAY,        /* Mar */
  159.     91 * SECS_PER_DAY,        /* Apr */
  160.     121 * SECS_PER_DAY,        /* May */
  161.     152 * SECS_PER_DAY,        /* Jun */
  162.     182 * SECS_PER_DAY,        /* Jul */
  163.     213 * SECS_PER_DAY,        /* Aug */
  164.     244 * SECS_PER_DAY,        /* Sep */
  165.     274 * SECS_PER_DAY,        /* Oct */
  166.     305 * SECS_PER_DAY,        /* Nov */
  167.     335 * SECS_PER_DAY,        /* Dec */
  168. };
  169.  
  170.  
  171.  
  172. /*
  173.  *----------------------------------------------------------------------
  174.  *
  175.  * Timer_TimerInit --
  176.  *
  177.  *    Initialize the ICM7170 chip.
  178.  *
  179.  *    N.B. This routine must be called before Timer_TimerStart.
  180.  *
  181.  * Results:
  182.  *    None.
  183.  *
  184.  * Side effects:
  185.  *    The timer is initialized and ready to start ticking.
  186.  *
  187.  *----------------------------------------------------------------------
  188.  */
  189.  
  190. /*ARGSUSED*/
  191. void
  192. Timer_TimerInit(timer)
  193.     unsigned short    timer;        /* Ignored for Sun-4 version. */
  194. {
  195.     static Boolean init = FALSE;
  196.     unsigned char c;
  197.  
  198.     if (!init) {
  199.     init = TRUE;
  200.     /*
  201.      * Register our call back function.
  202.      */
  203.     Mach_SetHandler(10, Timer_TimerServiceInterrupt, (ClientData) 0);
  204.     Mach_SetHandler(14, Timer_TimerServiceInterrupt, (ClientData) 0);
  205.  
  206.     /*
  207.      * Tell the chip to prevent interrupts.
  208.      */
  209.     timerIntrState = INTR_DISABLE;
  210.     timerRegsPtr->commandReg = IntersilCommand(RUN, timerIntrState);
  211.  
  212.     /*
  213.      * Tell the chip to cause periodic interrupts.
  214.      */
  215.     timerRegsPtr->interruptReg = TIMER_INTR_FREQ;
  216.  
  217.     /*
  218.      * Read the chip's interrupt register to clear any pending inerrupts.
  219.      */
  220.     c = timerRegsPtr->interruptReg;
  221. #ifdef lint
  222.     c = c;
  223. #endif
  224.     }
  225. }
  226.  
  227.  
  228. /*
  229.  *----------------------------------------------------------------------
  230.  *
  231.  * Timer_TimerStart --
  232.  *
  233.  *    Start the timer so it will cause periodic interrupts.
  234.  *    N.B. The timer must have been initialized with Timer_TimerInit
  235.  *    before this routine is called.
  236.  *
  237.  * Results:
  238.  *    None.
  239.  *
  240.  * Side effects:
  241.  *    The timer starts ticking.
  242.  *
  243.  *----------------------------------------------------------------------
  244.  */
  245.  
  246. void
  247. Timer_TimerStart(timer)
  248. unsigned short timer;
  249. {
  250.     if (timer == TIMER_CALLBACK_TIMER) {
  251.     callbackIntrsWanted = TRUE;
  252.     } else if (timer == TIMER_PROFILE_TIMER) {
  253.     profileIntrsWanted = TRUE;
  254.     } else {
  255.     panic("Timer_TimerStart: unknown timer %d\n", timer);
  256.     }
  257.     if (!timerActive) {
  258.     timerActive = TRUE;
  259.     /*
  260.      * Tell the chip to start counting and allow it to cause interrupts.
  261.      */
  262.     timerIntrState = INTR_ENABLE;
  263.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_ENABLE);
  264.  
  265.     /*
  266.      * Enable timer interrupts in the system's interrupt register.
  267.      */
  268.  
  269.     *Mach_InterruptReg |= MACH_ENABLE_TIMER_INTR_LEVEL;
  270.     }
  271. }
  272.  
  273.  
  274. /*
  275.  *----------------------------------------------------------------------
  276.  *
  277.  * Timer_TimerInactivate --
  278.  *
  279.  *    Stops the timer so that it will not cause interrupts.
  280.  *
  281.  * Results:
  282.  *    None.
  283.  *
  284.  * Side effects:
  285.  *    The timer is stopped.
  286.  *
  287.  *----------------------------------------------------------------------
  288.  */
  289.  
  290. void
  291. Timer_TimerInactivate(timer)
  292.     register unsigned short timer;
  293. {
  294.     if (timer == TIMER_CALLBACK_TIMER) {
  295.     callbackIntrsWanted = FALSE;
  296.     } else if (timer == TIMER_PROFILE_TIMER) {
  297.     profileIntrsWanted = FALSE;
  298.     } else {
  299.     panic("Timer_TimerInactivate: unknown timer %d\n", timer);
  300.     }
  301.  
  302.     /*
  303.      * If neither type of timer interrupt is wanted, then disable
  304.      * timer interrupts.
  305.      */
  306.  
  307.     if (!callbackIntrsWanted && !profileIntrsWanted) {
  308.     timerActive = FALSE;
  309.     *Mach_InterruptReg &= ~MACH_ENABLE_TIMER_INTR_LEVEL;
  310.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_DISABLE);
  311.     }
  312. }
  313.  
  314.  
  315. /*
  316.  *----------------------------------------------------------------------
  317.  *
  318.  * Timer_TimerGetStatus --
  319.  *
  320.  *    Clears the interrupt pending bit in the interrupt register
  321.  *    and reads the interrupt status register (ISR) of the chip.
  322.  *    The ISR must be read in order to reset the interrupt, according
  323.  *    to the Intersil data sheet (p.6, "Periodic Interrupts").
  324.  *    (It seems that the value is always 0.) According to the
  325.  *    Sun-3 architure manual (p.31), the level-5 bit in the interrupt 
  326.  *    register must be toggled to clear the interrupt.
  327.  *
  328.  * Results:
  329.  *    The value of the status register.
  330.  *
  331.  * Side effects:
  332.  *    The interrupt is cleared.
  333.  *
  334.  *----------------------------------------------------------------------
  335.  */
  336.  
  337. static unsigned short
  338. Timer_TimerGetStatus()
  339. {
  340.     unsigned char statusReg;
  341.     unsigned char intrReg;
  342.  
  343.     intrReg = *Mach_InterruptReg & MACH_ENABLE_LEVEL14_INTR;
  344.  
  345.     *Mach_InterruptReg &= ~(MACH_ENABLE_TIMER_INTR_LEVEL | 
  346.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  347.     statusReg = timerRegsPtr->interruptReg;
  348.  
  349.     *Mach_InterruptReg |= (MACH_ENABLE_TIMER_INTR_LEVEL | 
  350.                 MACH_ENABLE_ALL_INTERRUPTS | intrReg);
  351.     /*
  352.      * Read the chip again in case an obscure race condition occurs.
  353.      * (This is how Sun handles it.)
  354.      */
  355.     statusReg = timerRegsPtr->interruptReg;
  356.  
  357.     return(statusReg);
  358. }
  359.  
  360.  
  361. /*
  362.  *----------------------------------------------------------------------
  363.  *
  364.  * Timer_TimerExamineStatus --
  365.  *
  366.  *    Assuming the interrupt is valid, return TRUE or FALSE if 
  367.  *    the interrupt is or is not allowed for the specified timer.
  368.  *    (The status register is always 0 on the Sun-3 so we can't tell
  369.  *    if the chip really did interrupt.)
  370.  *
  371.  *    This routine is used to decrease the frequency of
  372.  *    a virtual timer. The callback timer's frequency is
  373.  *    one-half of the real timer's frequency.
  374.  *
  375.  * Results:
  376.  *    TRUE        if the timer interrupted.
  377.  *    FALSE        if the timer did not interrupt.
  378.  *
  379.  * Side effects:
  380.  *    The callback virtual timer's toggle is changed.
  381.  *
  382.  *----------------------------------------------------------------------
  383.  */
  384.  
  385. /*ARGSUSED*/
  386. static Boolean
  387. Timer_TimerExamineStatus(statusReg, timer, spuriousPtr)
  388.     unsigned char statusReg;    /* Ignored because it is always 0. */
  389.     unsigned int timer;        /* Virtual Timer # */
  390.     Boolean *spuriousPtr;    /* Always set FALSE. */
  391. {
  392.     static Boolean callbackTimerToggle = FALSE;
  393.  
  394.     /*
  395.      * Assume we never get a spurious interrupt because the statusReg
  396.      * value is always 0 on the Sun-3. 
  397.      */
  398.     *spuriousPtr = FALSE;
  399.  
  400.     if (timer == TIMER_CALLBACK_TIMER) {
  401.     /*
  402.      * Cut the timer's frequency in half.
  403.      */
  404.     callbackTimerToggle = !callbackTimerToggle;
  405.     return(callbackTimerToggle);
  406.     } else if (timer == TIMER_PROFILE_TIMER) {
  407.     if (profileIntrsWanted) {
  408.         return(TRUE);
  409.     } else {
  410.         return(FALSE);
  411.     }
  412.     } else {
  413.     printf("Timer_TimerExamineStatus: unknown timer %d\n", 
  414.                 timer);
  415.     return(FALSE);
  416.     }
  417. }
  418.  
  419. int    testCounter = 0;
  420.  
  421.  
  422. /*
  423.  *----------------------------------------------------------------------
  424.  *
  425.  *  Timer_TimerServiceInterrupt --
  426.  *
  427.  *      This routine is called at every timer interrupt. 
  428.  *      It calls the timer callback queue handling if the callback timer 
  429.  *    expired and calls the profiling interrupt handling if the 
  430.  *    profile callback timer expired.
  431.  *
  432.  *  Results:
  433.  *    None.
  434.  *
  435.  *  Side Effects:
  436.  *    Routines on the timer queue may cause side effects. Profile
  437.  *    collect may take place. 
  438.  *    
  439.  *
  440.  *----------------------------------------------------------------------
  441.  */
  442.  
  443. /*ARGSUSED*/
  444. int
  445. Timer_TimerServiceInterrupt(dummy, pc)
  446.     int            dummy;        /* unused clientData */
  447.     unsigned int    pc;        /* Only for sun4 version. */
  448.     /*
  449.      *  Determine if the callback and profile timers have expired.
  450.      *  Timer_TimerExamineStatus has the side effect of clearing the timer's
  451.      *  "cause interrupt" bit if it was set.
  452.      *
  453.      *  The profile timer is checked first because routines on the callback
  454.      *  queue might cause a delay in collecting profiling information.
  455.      */
  456.  
  457.     int profiled = FALSE;
  458.     unsigned short timerStatus =  Timer_TimerGetStatus();
  459.     Boolean spurious;
  460.  
  461.     if (Timer_TimerExamineStatus(timerStatus, TIMER_PROFILE_TIMER, &spurious)) {
  462.         TIMER_PROFILE_ROUTINE(pc);
  463.         profiled = TRUE;
  464. #       ifdef GATHER_STAT
  465.         timer_Statistics.profile++;
  466. #       endif
  467.     }
  468.  
  469.     if (Timer_TimerExamineStatus(timerStatus, TIMER_CALLBACK_TIMER, &spurious))
  470. {
  471.         TIMER_CALLBACK_ROUTINE(interval, time);
  472.     } else {
  473.         if (!profiled) {
  474.  
  475.             /*
  476.              * An unwanted timer interrupt was received but it wasn't
  477.              * spurious (this is o.k. -- see devTimerSun3.c).
  478.              */
  479.             if (!spurious) {
  480.                 return 0;
  481.             }
  482.  
  483.             /* Spurious interrupt!!! */
  484. #ifdef GATHER_STAT
  485.              timer_Statistics.spurious++;
  486. #endif
  487.  
  488.             printf("%c", 7);    /* ring the bell */
  489.  
  490.         }
  491.     }
  492.     return 0;
  493. }
  494.  
  495.  
  496. /*
  497.  *----------------------------------------------------------------------
  498.  *
  499.  * Timer_CounterInit --
  500.  *
  501.  *    Initializes the chip's free-running counters.
  502.  *    The STOP command stops the counter and the RUN command turns
  503.  *    it back on.
  504.  *
  505.  * Results:
  506.  *    None.
  507.  *
  508.  * Side effects:
  509.  *    None.
  510.  *
  511.  *----------------------------------------------------------------------
  512.  */
  513.  
  514. void
  515. Timer_CounterInit()
  516. {
  517.     timerRegsPtr->commandReg = IntersilCommand(STOP, timerIntrState);
  518. #ifdef sun4
  519.     timerRegsPtr->counter.hundredths = initialCounter.hundredths;
  520.     timerRegsPtr->counter.hours = initialCounter.hours;
  521.     timerRegsPtr->counter.minutes = initialCounter.minutes;
  522.     timerRegsPtr->counter.seconds = initialCounter.seconds;
  523.     timerRegsPtr->counter.month = initialCounter.month;
  524.     timerRegsPtr->counter.day = initialCounter.day;
  525.     timerRegsPtr->counter.year = initialCounter.year;
  526.     timerRegsPtr->counter.dayOfWeek = initialCounter.dayOfWeek;
  527. #else
  528.     timerRegsPtr->counter = initialCounter;
  529. #endif
  530.     timerRegsPtr->commandReg = IntersilCommand(RUN, timerIntrState);
  531. }
  532.  
  533.  
  534. /*
  535.  *----------------------------------------------------------------------
  536.  *
  537.  * Timer_GetCurrentTicks --
  538.  *
  539.  *    Read the contents of the counters. Interrupts are assumed
  540.  *    to be disabled to assure that the counters are read atomically.
  541.  *
  542.  * Results:
  543.  *    None.
  544.  *
  545.  * Side effects:
  546.  *    None.
  547.  *
  548.  *----------------------------------------------------------------------
  549.  */
  550.  
  551. void
  552. Timer_GetCurrentTicks(timePtr)
  553.     Timer_Ticks    *timePtr;    /* Time from the counters. */
  554. {
  555.     IntersilCounters    counter;
  556.  
  557.     /*
  558.      * Read the chip's counters.
  559.      */
  560.  
  561. #ifdef sun4
  562.     counter.hundredths = timerRegsPtr->counter.hundredths;
  563.     counter.hours = timerRegsPtr->counter.hours;
  564.     counter.minutes = timerRegsPtr->counter.minutes;
  565.     counter.seconds = timerRegsPtr->counter.seconds;
  566.     counter.month = timerRegsPtr->counter.month;
  567.     counter.day = timerRegsPtr->counter.day;
  568.     counter.year = timerRegsPtr->counter.year;
  569.     counter.dayOfWeek = timerRegsPtr->counter.dayOfWeek;
  570. #else
  571.     counter = timerRegsPtr->counter;
  572. #endif
  573.     CountersToTime(&counter, timePtr);
  574. }
  575.  
  576.  
  577. /*
  578.  *----------------------------------------------------------------------
  579.  *
  580.  * CountersToTime --
  581.  *
  582.  *    Converts the values in the Intersil free-running counters
  583.  *    to a time value.
  584.  *
  585.  * Results:
  586.  *    None.
  587.  *
  588.  * Side effects:
  589.  *    None.
  590.  *
  591.  *----------------------------------------------------------------------
  592.  */
  593.  
  594. static void
  595. CountersToTime(counterPtr, timePtr)
  596.     register IntersilCounters    *counterPtr;
  597.     register Time        *timePtr;
  598. {
  599.     register int seconds = 0;
  600.     register int *accumPtr;
  601.  
  602.     if (counterPtr->year != 0) {
  603.     seconds += (counterPtr->year * SECS_PER_YEAR) +
  604.            (((counterPtr->year + 3) / 4) * SECS_PER_DAY);
  605.     }
  606.  
  607.     /*
  608.      * Is it a leap year?
  609.      */
  610.     if ((counterPtr->year % 4) == 0) {
  611.     accumPtr = accumSecsPerMonthLeap;
  612.     } else {
  613.     accumPtr = accumSecsPerMonth;
  614.     }
  615.  
  616.     timePtr->seconds = seconds +
  617.         accumPtr[counterPtr->month] +
  618.         ((counterPtr->day - 1) * SECS_PER_DAY) +
  619.         (counterPtr->hours * SECS_PER_HOUR) +
  620.         (counterPtr->minutes * 60) +
  621.         counterPtr->seconds;
  622.     timePtr->microseconds = (counterPtr->hundredths * HUNDREDTH_SECOND);
  623. }
  624.  
  625.  
  626.  
  627. /*  @#@#@#@#@#@#@#@#@#@#@    DEBUGGING CODE    @#@#@#@#@#@#@#@#@#@#@  */
  628.  
  629. /*
  630.  *----------------------------------------------------------------------
  631.  *
  632.  * Timer_TimerGetInfo --
  633.  *
  634.  *    Debugging routine to print the contents of the free-running
  635.  *    counters.
  636.  *
  637.  * Results:
  638.  *    None.
  639.  *
  640.  * Side effects:
  641.  *    None.
  642.  *
  643.  *----------------------------------------------------------------------
  644.  */
  645.  
  646. /*ARGSUSED*/
  647. void
  648. Timer_TimerGetInfo(data)
  649.     ClientData    data;        /* Ignored. */
  650. {
  651.     IntersilCounters  counter;
  652.     Time    time;
  653.  
  654.     if ((int) data == 1) {
  655.     DISABLE_INTR();
  656.     timerRegsPtr->commandReg = IntersilCommand(RUN, INTR_ENABLE);
  657.     ENABLE_INTR();
  658.     return;
  659.     }
  660.  
  661.     DISABLE_INTR();
  662.     counter = timerRegsPtr->counter;
  663.     ENABLE_INTR();
  664.  
  665.     printf("Hundredths    %d\n", counter.hundredths);
  666.     printf("Seconds        %d\n", counter.seconds);
  667.     printf("Minutes        %d\n", counter.minutes);
  668.     printf("Hours        %d\n", counter.hours);
  669.     printf("Day        %d\n", counter.day);
  670.     printf("Month        %d\n", counter.month);
  671.     printf("Year        %d\n", counter.year);
  672.     printf("Day of Week    %d\n", counter.dayOfWeek);
  673.  
  674.     CountersToTime(&counter, &time);
  675.     printf("Time:    %d.%06u\n", time.seconds, time.microseconds);
  676. }
  677.  
  678. #ifdef NOT_USED
  679.  
  680. static void
  681. TimeToCounters(time, counterPtr)
  682.     Time    time;
  683.     register IntersilCounters    *counterPtr;
  684. {
  685.     int    *accumPtr;
  686.     register int seconds;
  687.  
  688. #define SECS_SINCE_1970_FOR(year) \
  689. (((year - 1970) * SECS_PER_YEAR) + ((((year - 1970) + 3) / 4) * SECS_PER_DAY))
  690.  
  691.     seconds = time.seconds - SECS_SINCE_1970_FOR(1984);
  692.  
  693.     if (seconds < 0) {
  694.     printf( "Tried to set time before 1984\n");
  695.     return;
  696.     }
  697.  
  698.     counterPtr->year = seconds / SECS_PER_YEAR;
  699.     seconds %= SECS_PER_YEAR;
  700.     seconds -= ((counterPtr->year + 3) / 4) * SECS_PER_DAY;
  701.  
  702.     if ((counterPtr->year % 4) == 0) {
  703.     accumPtr = accumSecsPerMonthLeap;
  704.     } else {
  705.     accumPtr = accumSecsPerMonth;
  706.     }
  707.  
  708.     for (month = 1; month < 13; month++) {
  709.     if (seconds < accumPtr[month]) {
  710.         seconds -= accumPtr[month];
  711.         counterPtr->month = month;
  712.         break;
  713.     }
  714.     }
  715.     counterPtr->day = (seconds / SECS_PER_DAY) + 1;
  716.     seconds %= SECS_PER_DAY;
  717.     counterPtr->hours = seconds / SECS_PER_HOUR;
  718.     seconds %= SECS_PER_HOUR;
  719.     counterPtr->minutes = seconds / 60;
  720.     counterPtr->seconds = seconds % 60;
  721.  
  722.     counterPtr->tenths = time.microseconds / TENTH_SECOND;
  723.     counterPtr->hundredths = 
  724.         (time.microseconds % TENTH_SECOND) / HUNDREDTH_SECOND;
  725. }
  726. #endif NOT_USED
  727.  
  728. /*
  729.  *----------------------------------------------------------------------
  730.  *
  731.  * TimerHardwareUniversalTimeInit --
  732.  *
  733.  *     Not implemented yet.
  734.  *
  735.  * Results:
  736.  *    None.
  737.  *
  738.  * Side effects:
  739.  *    None.
  740.  *
  741.  *----------------------------------------------------------------------
  742.  */
  743.  
  744. /*ARGSUSED*/
  745. void
  746. TimerHardwareUniversalTimeInit(timePtr, localOffsetPtr, DSTPtr)
  747.     Time *timePtr;        /* Buffer to hold universal time. */
  748.     int  *localOffsetPtr;    /* Buffer to hold local offset. */
  749.     Boolean *DSTPtr;        /* Buffer to hold DST allowed flag. */
  750. {
  751. }
  752.  
  753. /*
  754.  *----------------------------------------------------------------------
  755.  *
  756.  * TimerSetHardwareUniversalTime --
  757.  *
  758.  *    Not implemented yet.
  759.  *
  760.  * Results:
  761.  *    None.
  762.  *
  763.  * Side effects:
  764.  *    None.
  765.  *
  766.  *----------------------------------------------------------------------
  767.  */
  768.  
  769. /*ARGSUSED*/
  770. void
  771. TimerSetHardwareUniversalTime(timePtr, localOffset, DST)
  772.     Time *timePtr;        /* universal time. */
  773.     int  localOffset;        /* local offset. */
  774.     Boolean DST;        /* DST allowed flag. */
  775. {
  776. }
  777.  
  778.